package com.anjie.powerproject.controller;

import com.anjie.powerproject.common.Result;
import com.anjie.powerproject.entity.Point;
import com.anjie.powerproject.entity.TaskConfig;
import com.anjie.powerproject.service.PointService;
import com.anjie.powerproject.service.TaskConfigService;
import com.anjie.powerproject.strategy.utils.DateUtils;
import com.anjie.powerproject.util.ExcelUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.persistence.criteria.CriteriaBuilder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;


@Controller
@RequestMapping("point")
public class PointController {
    @Autowired
    JdbcTemplate jdbcTemplate;
    @Autowired
    PointService pointService;
    @Autowired
    TaskConfigService taskConfigService;

    /**
     * 根据id获取点位的信息，并跳转到查看界面
     * @param id
     * @param model
     * @return
     */
    @GetMapping("/getInfo/{id}")
    private String getPointInfo(@PathVariable("id") Integer id, Model model){
        Point point = pointService.getPointById(id);
        model.addAttribute("point",point);
        return "pointInfo";
    }

    /**
     * 根据点位id获取点位，并跳转到点位修改页面
     * @param id
     * @param model
     * @return
     */
    @GetMapping("/update/{id}")
    private String updatePoint1(@PathVariable("id") Integer id,Model model){
        Point point = pointService.getPointById(id);
        model.addAttribute("point",point);
        return "pointEdit";
    }

    /**
     * 获取所有点位list
     * 前端点位下拉框使用该接口
     * @return
     */
    @RequestMapping(value = "/getAll")
    @ResponseBody
    public Result getAll(){
        List<Point> sortedPointList=pointService.getPointList().stream()
                .sorted(Comparator.comparing(Point::getId))
                .collect(Collectors.toList());
        return new Result(sortedPointList,true,1,"查询成功");
    }

    /**
     * 通过条件查询 point数据,参数pointName,devCode可为空
     * @param pointName
     * @param devCode
     * @return
     */
    @RequestMapping(value = "/getByConditions")
    @ResponseBody
    public Result  getPointListByConditions(
            @RequestParam(value = "pointName", required = false, defaultValue = "") String pointName,
            @RequestParam(value = "devCode", required = false, defaultValue = "") String devCode){
//        System.out.println(pointService.getPointListByConditions(pointName,devCode).size());

        return new Result(pointService.getPointListByConditions(pointName,devCode),true,1,"查询成功");
    }

    @RequestMapping(value = "/update", params = {"pointName","devCode","id"})
    @ResponseBody
    public Result updatePoint(String pointName,String devCode,Integer id){
        //如果修改了devCode，要对该点位对应的taskConfig进行同步修改
        Point point=pointService.getPointById(id);
        if(!pointName.equals(point.getPointName())){ //修改了pointName,要查询是否有点位同名
            if(0!=pointService.pointNameIsExist(pointName)){
                //重复pointName
                return new Result(null,false,0,"点位的名字代码或者点位代码已存在！添加失败！");
            }
        }
        if(!devCode.equals(point.getDevCode())){//修改了devCode，要查询是否有点位存在相同的devCode
            if(0!=pointService.pointDevCodeIsExist(devCode)){
                //重复devCode
                return new Result(null,false,0,"点位的名字代码或者点位代码已存在！添加失败！");
            }
        }
        if(1==pointService.updatePoint(pointName,devCode,id))
            return new Result(null,true,1,"修改成功");
        else
            return new Result(null,false,0,"修改失败");
    }

    @RequestMapping(value = "/delete", params = {"id"})
    @ResponseBody
    public Result deletePoint(Integer id){
        //删除点位同时删除点位对应的配置数据（task_config），
        if (pointService.deletePointById(id))
            return new Result(null,true,1,"删除成功");
        else
            return new Result(null,false,0,"删除失败");
    }

    @RequestMapping(value = "/add", params = {"pointName","devCode"})
    @ResponseBody
    public Result addPoint(String pointName,String devCode) {
        if (0 != pointService.pointIsExist(pointName, devCode)) {
            //重复pointName或devCode
            return new Result(null, false, 0, "点位名字或者点位代码已存在！添加失败！");
        }
        Point pointAdd = new Point(pointName, devCode);
        Point point = pointService.add(pointAdd);
        if (point == null)
            return new Result(null, false, 0, "添加点位失败");
        return new Result(null,true,1,"添加成功");
    }

//    @RequestMapping(value = "/add", params = {"pointName","devCode"})
//    @ResponseBody
//    public Result addPoint(String pointName,String devCode){
//        if(0!=pointService.pointIsExist(pointName,devCode)){
//            //重复pointName或devCode
//            return new Result(null,false,0,"点位的名字代码或者点位代码已存在！添加失败！");
//        }
//        //添加点位的同时还要添加taskConfig（点位配置，通过devCode）关联
//        TaskConfig taskConfig=new TaskConfig();
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd-HH:mm:ss");
//        String dateString=sdf.format(new Date());
//        Point pointAdd=new Point(pointName,devCode);
//        Point point=pointService.add(pointAdd);
//        if(point!=null){
//            taskConfig.setDevCode(devCode);
//            taskConfig.setUpdateTime(dateString);
//            taskConfig.setPointId(point.getId());
//        }else {
//            return new Result(null,false,0,"添加点位失败");
//        }
//        TaskConfig tmp=taskConfigService.saveAndFlush(taskConfig);
//
//        if(tmp!=null)
//            return new Result(null,true,1,"添加成功");
//        else
//            return new Result(null,false,0,"添加点位配置信息失败");
//    }


    public static <T> List<T> getDuplicateElements(List<T> list) {
        return list.stream()
                .collect(Collectors.toMap(e -> e, e -> 1, (a, b) -> a + b)) // 获得元素出现频率的 Map，键为元素，值为元素出现的次数
                .entrySet().stream() // Set<Entry>转换为Stream<Entry>
                .filter(entry -> entry.getValue() > 1) // 过滤出元素出现次数大于 1 的 entry
                .map(entry -> entry.getKey()) // 获得 entry 的键（重复元素）对应的 Stream
                .collect(Collectors.toList()); // 转化为 List
    }
    /**
     * 接收Excel文件，批量导入point数据，使用jdbcTemplate.batchUpdate方法，效率优于JPA.saveAll
     * @param pointFile
     * @return
     */
    @RequestMapping(value = "/batchAdd",method = RequestMethod.POST)
    @ResponseBody
    public Result batchAddPoint(@RequestParam("pointFile") MultipartFile pointFile) {
//        System.out.println("上传文件成功--------"+pointFile.getOriginalFilename());
//        保存文件并取得文件路径
//        String path = (String)fileService.upload(file).getContent();
//        读取Excel数据
        List<List<String>> lists = ExcelUtil.readExcel(pointFile);
//        System.out.println(lists.size()+"\n"+lists.get(1).size()+"\n\n\n\n\n");
//        System.out.println(lists.get(0)+lists.get(1)+lists.get(2)+"\n\n\n\n\n");

        //将数据读出,存入数据库
        List<String> pointDevCodeList=new ArrayList<>();
        List<String> pointNameList=new ArrayList<>();
        List<Point> pointList=new ArrayList<>();
        for (int i=1;i<lists.size();i++){
            Point point=new Point();
            point.setDevCode(lists.get(i).get(0));
            point.setPointName(lists.get(i).get(1));
            pointList.add(point);
//            pointDevCodeList.add(lists.get(i).get(0));
//            pointNameList.add(lists.get(i).get(1));
        }

        //name和devCode中有一个为空或者都为空的数据，放在一起
        List<Point> BlankPointList = pointList.stream().filter(item -> !StringUtils.isNotBlank(item.getPointName())||!StringUtils.isNotBlank(item.getDevCode())).collect(Collectors.toList());

        //name和devCode中有一个为空的数据，放在一起
        List<Point> NotAllBlankPointList = BlankPointList.stream().filter(item -> StringUtils.isNotBlank(item.getPointName())||StringUtils.isNotBlank(item.getDevCode())).collect(Collectors.toList());

        if(NotAllBlankPointList.size()>0){ //有不符合规则的数据
            return new Result(null, false, 0, "点位名字和点位代码不能为空！");
        }
        //过滤name和devCode中有一个为空或者都为空的数据
        pointList=pointList.stream().filter(item -> StringUtils.isNotBlank(item.getPointName())||StringUtils.isNotBlank(item.getDevCode())).collect(Collectors.toList());
        for (Point point:pointList){
            pointDevCodeList.add(point.getDevCode());
            pointNameList.add(point.getPointName());
        }

        //查询excel表中是否有点位重复
        List<String> duplicateDevCode=getDuplicateElements(pointDevCodeList);
        List<String> duplicateName=getDuplicateElements(pointNameList);
        List<Integer> duplicatePointPositionList=new ArrayList<>();
        boolean excelDuplicateFlag=false;
        if(duplicateDevCode.size()>0){//excel文件中devCode点位代码重复
//            System.out.println("duplicateDevCode: "+duplicateDevCode);
            for (String s:duplicateDevCode) {
                duplicatePointPositionList.add(pointDevCodeList.indexOf(s)+1);
            }
            excelDuplicateFlag=true;
        }
        if(duplicateName.size()>0){//excel文件中点位名字重复
//            System.out.println("duplicateName:"+duplicateName);
            for (String s:duplicateName) {
                int pos=pointNameList.indexOf(s)+1;
                if(duplicatePointPositionList.indexOf(pos)==-1)  //不与筛选devcode时筛选出的点位重复
                    duplicatePointPositionList.add(pos);
            }
            excelDuplicateFlag=true;
        }
        if(excelDuplicateFlag){
            String errMsg="第";
            for (int dupPoint:duplicatePointPositionList) {
                errMsg+=(String.valueOf(dupPoint)+", ");
            }
//            System.out.println(errMsg+"-------"+errMsg.length());
            errMsg=errMsg.substring(0,errMsg.length()-2)+"行点位重复！";
            return new Result(null, false, 0, errMsg);
        }

        //检查是否有重复点位
        String duplicatePointPosition="";
        boolean duplicateFlag=false;
        for (int i=0;i<pointList.size();i++) {
            if ((0 != pointService.pointIsExist(pointList.get(i).getPointName(), pointList.get(i).getDevCode()))) {
                //重复pointName或devCode
                duplicatePointPosition+=String.valueOf(i + 1)+", ";
                duplicateFlag=true;
            }
        }
        if(duplicateFlag){
            duplicatePointPosition=duplicatePointPosition.substring(0,duplicatePointPosition.length()-2);
            String msg="Excel表中第" + duplicatePointPosition + "行点位的名字代码或者点位代码已存在！";
            return new Result(null, false, 0, msg);
        }

//        List<TaskConfig> taskConfigList=new ArrayList<>();
//        for (int i=0;i<pointList.size();i++){
//            if(0!=pointService.pointIsExist(pointList.get(i).getPointName(),pointList.get(i).getDevCode())){
//                //重复pointName或devCode
//                return new Result(null,false,0,"Excel表中第"+i+2+"行点位的名字代码或者点位代码已存在！");
//            }else{//不重复，添加taskConfig
//                TaskConfig taskConfig=new TaskConfig();
//                taskConfig.setUpdateTime(dateString);
//                taskConfig.setDevCode(pointList.get(i).getDevCode());
//                taskConfigList.add(taskConfig);
////                taskConfigService.saveAndFlush(taskConfig);
//            }
//        }

        //批量插入点位
        for (int i=0;i<pointList.size();i++){
            Point point=pointService.add(pointList.get(i));
            if(point==null)
                return new Result(null,false,0,"添加点位失败");
        }

//        String sql_task_config = "INSERT INTO task_config (dev_code,updatetime) VALUES (?,?)";
//        jdbcTemplate.batchUpdate(sql_task_config, new BatchPreparedStatementSetter() {
//            public void setValues(PreparedStatement ps, int i) throws SQLException {
//                String devCode = taskConfigList.get(i).getDevCode();
//                String updateTime = taskConfigList.get(i).getUpdateTime();
//                ps.setString(1, devCode);
//                ps.setString(2, updateTime);
//            }
//            public int getBatchSize() {
//                return taskConfigList.size();
//            }
//        });
//
//        String sql = "INSERT INTO point (dev_code, point_name ) VALUES (?,?)";
////        System.out.println(pointList);
//        jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
//            public void setValues(PreparedStatement ps, int i) throws SQLException {
//                String devCode = pointList.get(i).getDevCode();
//                String pointName = pointList.get(i).getPointName();
//                ps.setString(1, devCode);
//                ps.setString(2, pointName);
//            }
//            //指定数据大小
//            public int getBatchSize() {
//                return pointList.size();
//            }
//        });

        return new Result(null,true,1,"添加成功");
    }

    /**
     * 从数据库中获取所有的 Point信息，并写入excel，传输给前端
     * @param response
     * @param request
     */
    @RequestMapping(value = "/excel/exportPointInfo",method = RequestMethod.GET)
    public void ExportBankCkeckInfo(HttpServletResponse response, HttpServletRequest request){
        //这里是打印的时间间隔。可忽略
//        String start=request.getParameter("start");
//        String end=request.getParameter("end");
//        System.out.println("打印的起始日期为："+start+"，打印的结束日期为："+end);
        //得到所有要导出的数据
        List<Point> pointlist = pointService.getPointList();
        //定义导出的excel名字
        String excelName = "点位数据表";

        //获取需要转出的excel表头的map字段   前面放实体类的字段名，后面是excel表的列名
        LinkedHashMap<String, String> fieldMap = new LinkedHashMap<>();
        fieldMap.put("id","ID");
        fieldMap.put("pointName","点位名称");
        fieldMap.put("devCode","点位代码");

        //导出信息
        new ExcelUtil().export(excelName,pointlist,fieldMap,response);
    }

    /**
     *查询所有点位代码并返回
     */
    @RequestMapping(value = "/getAllDevCode")
    @ResponseBody
    public Result getAllPointDevCode( ){
        List<Point> sortedPointList=pointService.getPointList().stream()
                .sorted(Comparator.comparing(Point::getId))
                .collect(Collectors.toList());
//        for (Point point:sortedPointList) {
//            System.out.println(point.getId()+" -------- "+ point.getPointName());
//        }
        return new Result(sortedPointList,true,1,"查询成功");
    }

    /**
     * 根据前端传来的devCode模糊搜索，并返回符合条件的devCode的List<String>
     */
    @RequestMapping(value = "/fuzzySelectDevCode",params = {"devCode"})
    @ResponseBody
    public Result fuzzySelectPointDevCode(String devCode){
        return new Result(pointService.fuzzySelectPointDevCode(devCode),true,1,"查询成功");
    }

}
